#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <direct.h>
#include <memory.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <process.h>
#include <Winsock2.h>
#include <assert.h>
#include <TCHAR.h>
#include <windows.h>

#include "cJSON.h"
#include "zq_device.h"
#include "zq_hal_simu.h"
extern ZqThreadHandle zq_main_task_hd;
// 引入每个任务句柄，供模拟器模拟多任务并行。
#if (ZQC_MAINBOARD_TYPE == CAT1_MBT_800G || ZQC_MAINBOARD_TYPE == CAT1_MBT_800K)
extern int zqc_main(void* param);
#define zq_app_main(param) zqc_main(param)
#elif (ZQC_MAINBOARD_TYPE == CAT1_MBT_HS2131)
extern int custom_app_init(void);
#define zq_app_main(param) custom_app_init()
#endif
#include "simu.h"

// 模拟一些辅助函数 -----------------------------------------------------------------------------------------------------------------
typedef struct {
	char com0[32];
	char com1[32];
	char com2[32];
	char com3[32];
} ZqSimuGenCfg;
static ZqSimuGenCfg* ReadCfgFile(void)
{
	static ZqSimuGenCfg cfg = {0,0,0,0};
	// read cfg file
	FILE* fp = fopen(".\\app\\zq_simu.config", "r");
	if (fp == NULL) return NULL;
	char buf[1024];
	buf[0] = 0;
	fread(buf, 1, 1024, fp);
	fclose(fp);
	// analyze
	cJSON* root = cJSON_Parse(buf);
	if (root == NULL) return NULL;
	do {
		// get port数组
		cJSON* ports = cJSON_GetObjectItemCaseSensitive(root, "cat1_port");
		if (!cJSON_IsArray(ports)) break;
		int array_size = cJSON_GetArraySize(ports);
		if (array_size != 2) break;
		cJSON* item = NULL;
		char* com = NULL;
		item = cJSON_GetArrayItem(ports, 0);
		if (!cJSON_IsString(item)) break;
		com = item->valuestring;
		if (com[0] == 'c' || com[0] == 'C') strcpy(cfg.com0, com);
		item = cJSON_GetArrayItem(ports, 1);
		if (!cJSON_IsString(item)) break;
		com = item->valuestring;
		if (com[0] == 'c' || com[0] == 'C') strcpy(cfg.com1, com);
		cJSON_Delete(root);
		return &cfg;
	} while (0);

	cJSON_Delete(root);
	return NULL;
}
// 模拟windows没有的strnstr
char* strnstr(char* org, char* target, int len)
{
	char tmp[4096 + 4];
	if (len >= 4096) return NULL;
	memcpy(tmp, org, len);
	tmp[len] = 0;
	char* p = strstr(tmp, target);
	if (p == NULL) return p;
	return (p - tmp + org);
}
// 模拟打印log时输出时间
const char* GetLocalTimeStrWin32(void)
{
	static char buf[28];
	time_t t = time(NULL);
	struct tm* tt = localtime(&t);
	tt->tm_year += 1900;
	tt->tm_mon += 1;
	int ms = t % 1000;
	sprintf(buf, "%04d/%02d/%02d-%02d:%02d:%02d:%03d", tt->tm_year, tt->tm_mon, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec, ms);
	return buf;
}

// 模拟设备参数 -----------------------------------------------------------------------------------------------------------------
const int simu_base_station[6][5] = { {460,0,20935,230580263,-110}, {460, 1, 20750, 84684343, -84}, {460, 0, 20953, 230580264, -97}, {460, 11, 16475, 66286646, -103}, {460, 11, 16475, 66286646, -103}, {460, 11, 16475, 66286646, -103} };

// 模拟串口 ---------------------------------------------------------------------------------------------------------------------
char uart_ports[16][32] = { 0 };
HANDLE uart_handles[16] = { 0 };
HANDLE pipe_read[16] = { 0 };
HANDLE pipe_write[16] = { 0 };
unsigned char uart_read_buff[16][UART_BUF_SIZE];
unsigned int uart_read_len[16] = { 0 };


//#pragma comment(linker, "/SUBSYSTEM:CONSOLE /ENTRY:wmainCRTStartup")
// 主函数 cat1.exe "串口1" "串口2"
// 控制台运行例子：cat1.exe "\\\\.\\COM31" "NULL"
int main(int argc, char* argv[])
{
	// 设置本地化，以支持多字节字符集
	setlocale(LC_ALL, "");

	// 设置启动窗口位置靠右, 不要挡住模拟器显示屏
	// win11缺省启动的不是控制台，是一个叫终端的东东， 所以不要用传统的GetConsoleWindow();得到hwnd
	char title[1024];
	GetConsoleTitle(title, 1024);
	HWND hwnd = FindWindow(NULL, title);
	if (hwnd != NULL) {
		SetWindowPos(hwnd, HWND_TOP, 600, 200, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
	}

	// 设置通讯串口
	if (argc < 2) {// 启动命令行没有带参数
		// try read from cfg file
		ZqSimuGenCfg* cfg = ReadCfgFile();
		if (cfg != NULL) {
			if (cfg->com0[0] != 0) strcpy(uart_ports[0], cfg->com0);
			if (cfg->com0[1] != 0) strcpy(uart_ports[1], cfg->com1);
		}
		else 
			strcpy(uart_ports[0], "\\\\.\\COM33");
	}
	else {
		if (argv[1][0] == '\\' || argv[1][0] == 'c' || argv[1][0] == 'C') strcpy(uart_ports[0], argv[1]);
		if (argv[2][0] == '\\' || argv[2][0] == 'c' || argv[2][0] == 'C') strcpy(uart_ports[1], argv[2]);
		if (argv[1][0] >= 0x30 && argv[1][0] <= 0x39) { // 数字，匿名管道
			char* write_str = strchr(argv[1], '+');
			assert(write_str);
			*write_str = '\0';
			pipe_read[0] = (void*)atoi(argv[1]);
			pipe_write[0] = (void*)atoi(write_str + 1);
		}
		if (argv[2][0] >= 0x30 && argv[2][0] <= 0x39) { // 数字，匿名管道
			char* write_str = strchr(argv[2], '+');
			assert(write_str);
			*write_str = '\0';
			pipe_read[1] = (void*)atoi(argv[2]);
			pipe_write[1] = (void*)atoi(write_str + 1);
		}
	}
	assert(uart_ports[0] != 0);
	// 初始化windows套接字
	WSADATA WsaData;
	WSAStartup(MAKEWORD(2, 2), &WsaData);
	// 延时2000ms，模拟cat1开机(700ms)+操作系统启动时间
	Sleep(2000);
	// 启动system 启动时间计时
	ZqGetSystemTickMs();
	// 调用APP入口函数
	zq_app_main(NULL);
	// 等待子线程
	pthread_join(zq_main_task_hd, NULL); // 任务模拟
	//pthread_join(*wifiscan_task, NULL); // 任务模拟
	//pthread_join(*basescan_task, NULL); // 任务模拟
	// 清除windows套接字
	WSACleanup();
}

